package com.ivybaby.ivy_baby_record;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
//import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.flutter.Log;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.view.TextureRegistry;

/** IvyBabyRecordPlugin */
public class IvyBabyRecordPlugin implements FlutterPlugin, MethodCallHandler {
  private static final String TAG = IvyBabyRecordPlugin.class.getSimpleName();
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private TextureRegistry registrar;
  private Context context;
  private Map<String, TextureRegistry.SurfaceTextureEntry> textureMap = new HashMap<>();
  private Map<String, Surface> surfaceMap = new HashMap<>();

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "ivy_baby_record");
    channel.setMethodCallHandler(this);
    //Log.setLogLevel(0);
    context = flutterPluginBinding.getApplicationContext();
    registrar = flutterPluginBinding.getTextureRegistry();
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("" + android.os.Build.VERSION.RELEASE);
    } else if (call.method.equals("getClientVersion")) {
      result.success(getAppVersion());
    } else if (call.method.equals("loadImage")) {
      if (call.arguments instanceof Map) {
        loadImage((String) ((Map) call.arguments).get("url"), result);
      } else {
        Log.i(TAG, "arguments not map");
      }
    } else if (call.method.equals("release")) {
      if (call.arguments instanceof Map) {
        releaseSurface((String) ((Map) call.arguments).get("url"), result);
      }
    } else if (call.method.equals("releaseList")) {
      if (call.arguments instanceof Map) {
        releaseSurfaces((List<String>) (((Map) call.arguments).get("url")), result);
      }
    } else {
      result.notImplemented();
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  private String getAppVersion() {
    PackageInfo packInfo = null;
    try {
      packInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
    } catch (Throwable e) {
      // TransactionTooLargeException
      e.printStackTrace();
    }
    String version = packInfo == null ? "1.0.0" : packInfo.versionName;
    Log.i(TAG, "getAppVersion version : " + version);
    return version;
  }

  private void loadImage(String url, Result result) {
    int resId = context.getResources().getIdentifier(url, "drawable", context.getPackageName());
    //Log.i(TAG, "loadImage resId : " + resId);

    TextureRegistry.SurfaceTextureEntry surfaceTextureEntry = textureMap.get(url);
    if (surfaceTextureEntry != null) {
      result.success(surfaceTextureEntry.id());
      return;
    }
    BitmapFactory.decodeResource (context.getResources(), resId);
    Bitmap resource = BitmapFactory.decodeResource (context.getResources(), resId);
    if (resource != null) {
      int bitmapWidth = resource.getWidth();
      int bitmapHeight = resource.getHeight();
      Rect rect = new Rect(0, 0, bitmapWidth, bitmapHeight);
      surfaceTextureEntry = registrar.createSurfaceTexture();
      //Log.i(TAG, "surfaceTextureEntry : " + surfaceTextureEntry.toString());
      SurfaceTexture surfaceTexture = surfaceTextureEntry.surfaceTexture();
      surfaceTexture.setDefaultBufferSize(bitmapWidth, bitmapHeight);
      Surface surface = new Surface(surfaceTexture);
      Canvas canvas = surface.lockCanvas(rect);
      canvas.drawBitmap(resource, null, rect, null);
      surface.unlockCanvasAndPost(canvas);
      surfaceMap.put(url, surface);
      textureMap.put(url, surfaceTextureEntry);
      Log.i(TAG, "loadImage surfaceTextureEntry : " + surfaceTextureEntry.id());
      result.success(surfaceTextureEntry.id());
    } else {
      Log.i(TAG, "loadImage failed : " + resId);
    }
  }

  private void releaseSurface(String url, Result result) {
    if (textureMap != null && !textureMap.isEmpty()) {
      Surface surface = surfaceMap.remove(url);
      if (surface != null) {
        try {
          surface.release();
        } catch (Throwable r) {
          r.printStackTrace();
        }
      }
      TextureRegistry.SurfaceTextureEntry surfaceTextureEntry = textureMap.remove(url);
      if (surfaceTextureEntry != null) {
        surfaceTextureEntry.release();
        result.success(true);
        Log.i(TAG, "releaseSurface " + url + " success");
      } else {
        result.success(false);
        Log.i(TAG, "releaseSurface failed");
      }
    }
  }

  private void releaseSurfaces(List<String> list, Result result) {
    if (list != null && list.size() > 0) {
      boolean success = true;
      for (String url : list) {
        if (textureMap != null && !textureMap.isEmpty()) {
          Surface surface = surfaceMap.remove(url);
          if (surface != null) {
            try {
              surface.release();
            } catch (Throwable r) {
              r.printStackTrace();
            }
          }
          TextureRegistry.SurfaceTextureEntry surfaceTextureEntry = textureMap.remove(url);
          if (surfaceTextureEntry != null) {
            try {
              surfaceTextureEntry.release();
              Log.i(TAG, "releaseSurface " + url + " success");
            } catch (Throwable r) {
              r.printStackTrace();
            }
          } else {
            success = false;
          }
        }
      }

      if (result != null) {
        result.success(success);
      }
    }
  }
}
